

#include "Filter.hpp"

#include <iostream>
#include <cmath>


using namespace com::toxiclabs::tsoc;
using namespace std;


Filter::~Filter()
{
	
}

/* static members */
vector<Filter *> FilterPool::filters;

Fog Fog::instance;

Gamma Gamma::instance;

//Dof Dof::instance;


Fog::Fog()
{
	
	name="Fog";
	
	FilterPool::filters.push_back(this);
	
	cout<<"Registered Fog filter"<<endl;
}

Fog::~Fog()
{
	
}

				
void Fog::Init(uint32_t * cbuffer,float * zbuffer,int width,int height)
{
	this->cbuffer=cbuffer;
	this->zbuffer=zbuffer;
	this->width=width;
	this->height=height;
	
	fog_color.Set(0.6f,0.6f,0.6f,1.0f);
}

void Fog::Process(int x,int y,int w,int h)
{
	/*
	for(int i=x;i!=(w+x);i++)
	{
		for(int j=y;j!=(h+y);j++)
		{
			uint32_t pixel = cbuffer[i+j*width];
			float depth = zbuffer[i+j*width];
			
			Color c(pixel);
			
			float factor = (depth/32.0f);
			
			Color m = fog_color * factor;
			c = c + m;
						
			
			cbuffer[i+j*width]=c.Pixel();
			
		}
	}
	*/
}


Gamma::Gamma()
{
	
	name="Gamma";
	
	FilterPool::filters.push_back(this);
	
	cout<<"Registered Gamma filter"<<endl;
}

Gamma::~Gamma()
{
	
}

				
void Gamma::Init(uint32_t * cbuffer,float * zbuffer,int width,int height)
{
	this->cbuffer=cbuffer;
	this->zbuffer=zbuffer;
	this->width=width;
	this->height=height;
	
	//creating lookup table
	
	
}

void Gamma::Process(int x,int y,int w,int h)
{
	float factor=0.6f;
	
	for(int i=x;i!=(w+x);i++)
	{
		for(int j=y;j!=(h+y);j++)
		{
			uint32_t pixel = cbuffer[i+j*width];
			
			
			Color c(pixel);
			
			c.r = pow(c.r,factor);
			c.g = pow(c.g,factor);
			c.b = pow(c.b,factor);
								
			
			cbuffer[i+j*width]=c.Pixel();
			
		}
	}
	
}

Dof::Dof()
{
	
	name="Dof";
	
	FilterPool::filters.push_back(this);
	
	cout<<"Registered Depth of field filter"<<endl;
}

Dof::~Dof()
{
	
}

				
void Dof::Init(uint32_t * cbuffer,float * zbuffer,int width,int height)
{
	this->cbuffer=cbuffer;
	this->zbuffer=zbuffer;
	this->width=width;
	this->height=height;
	
		
	
}

void Dof::Process(int x,int y,int w,int h)
{
	vector<uint32_t> aux(w*h);
	
	
	
	for(int i=x;i!=(w+x);i++)
	{
		for(int j=y;j!=(h+y);j++)
		{
			float depth = zbuffer[i+j*width];
			int distort;
			if(depth<14.0f)
			{
				aux[(i-x)+(j-y)*w]=cbuffer[i+j*width];
				continue;
			}
			
			distort=3+depth-14;
			if(distort>11)distort=11;
			
			vector<float> kernel1D = CreateKernel(distort);
			int sx = i - kernel1D.size()/2;
			int ex = i + kernel1D.size()/2;
			
			if(sx<0)sx=0;
			if(ex>=width)ex=width-1;
			
			int s = sx;
			Color c(cbuffer[s+j*width]);
			c=c * kernel1D[0];
			
			int n=1;
			
			for(int s=sx+1;s<=ex;s++)
			{
				Color p(cbuffer[s+j*width]);
				p=p * kernel1D[n];
				c=c+p;
				n++;
			}
			
			aux[(i-x)+(j-y)*w] = c.Pixel();
			
		}
	}
	
	//copy the whole chunk
	for(int i=x;i!=(w+x);i++)
	{
		for(int j=y;j!=(h+y);j++)
		{
			cbuffer[i+j*width]=aux[(i-x)+(j-y)*w];
		}
	}
	
	
}

vector<float> Dof::CreateKernel(int radius)
{
	vector<float> kernel1D(2*radius+1);
	
	float sigma = radius/2.0f;
	float sum = 0;
	for(int n=0;n<kernel1D.size();n++)
	{
		kernel1D[n]=exp( -(((n-radius)/(sigma))*((n-radius)/(sigma)))/2.0 );
		sum+=kernel1D[n];
	}
	
	for(int n=0;n<kernel1D.size();n++)
	{
		kernel1D[n]=kernel1D[n]/sum;
	}
	
	
	return kernel1D;
}

